import java.io.*;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket();
        // 超时时间
        socket.setSoTimeout(5000); // 5000ms
        socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(), 2000), 3000);

        System.out.println("已发起服务器连接，进入后续流程~");
        System.out.println("client information:" + socket.getLocalAddress() + "P:" + socket.getLocalPort());
        System.out.println("服务器端信息:" + socket.getInetAddress() + "P:" + socket.getPort());

        try {
            // send or receive data
            //
            todo(socket); // 发送数据
        } catch (Exception e) {
            System.out.println("异常关闭");
        }

        socket.close();
        System.out.println("客户端已退出~");
    }

    private static void todo(Socket client) throws IOException {

        /*
         * 构建键盘输入流
         */
        // InputStream 是一个抽象类
        InputStream in = System.in; // 控制台的输入
        BufferedReader input = new BufferedReader(new InputStreamReader(in)); // 装饰类

        // 得到socket输出流，转换为打印流
        OutputStream outputStream = client.getOutputStream();
        /**
         * PrintStream 是打印输出流，它继承于FilterOutputStream。
         * PrintStream 是用来装饰其它输出流。它能为其他输出流添加了功能，使它们能够方便地打印各种数据值表示形式。
         * 与其他输出流不同，PrintStream 永远不会抛出 IOException；它产生的IOException会被自身的函数所捕获并设置错误标记， 用户可以通过 checkError() 返回错误标记，从而查看PrintStream内部是否产生了IOException。
         * 另外，PrintStream 提供了自动flush 和 字符集设置功能。所谓自动flush，就是往PrintStream写入的数据会立刻调用flush()函数。
         */
        PrintStream socketPrintStream = new PrintStream(outputStream);
        // 将“输出流out”作为PrintStream的输出流，不会自动flush，并且采用默认字符集
        // 所谓“自动flush”，就是每次执行print(), println(), write()函数，都会调用flush()函数；
        // 而“不自动flush”，则需要我们手动调用flush()接口。


        // 得到socket输入流，转换为字符缓冲流
        InputStream inputStream = client.getInputStream();
        BufferedReader socketBufferedReader = new BufferedReader(new InputStreamReader(inputStream));

        boolean flag = true;
        do {
            // 键盘读取一行
            String str = input.readLine();

            // 发送到服务器
            socketPrintStream.println(str);

            String echo = socketBufferedReader.readLine(); // 从服务器读取一行

            if ("bye".equalsIgnoreCase(echo)) {
                //忽略大小写的比较，可以调用equalsIgnoreCase( )方法。当比较两个字符串时，它会认为A-Z和a-z是一样的
                flag = false;
            } else {
                System.out.println(echo);
            }
        } while (flag);

        // 资源释放
        socketBufferedReader.close();
        socketBufferedReader.close();
    }
}
